package com.xiaoban.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaoban.pojo.LoginSyUser;
import com.xiaoban.pojo.Users;
import com.xiaoban.service.UsersService;
import com.xiaoban.mapper.UsersMapper;
import com.xiaoban.utils.JwtUtil;
import com.xiaoban.utils.RedisCache;
import com.xiaoban.utils.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
* @author XiaoBanGe
* @description 针对表【sys_user(用户表)】的数据库操作Service实现
* @createDate 2024-03-15 17:35:58
*/
@Service
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements UsersService{

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisCache redisCache;



    /**
     * 用户单点登录
     * @param users 用户表单
     * @return 登录结果
     */
    @Override
    public ResponseResult Login(Users users) {
     /*创建一个 UsernamePasswordAuthenticationToken 对象，用于封装用户的认证信息
     这个对象包含了用户的用户名和密码，其中 user.getUserName() 是用户输入的用户名，user.getPassword() 是用户输入的密码*/
       UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(users.getUserName(), users.getPassword());
       /* 调用认证管理器 authenticationManager 的 authenticate 方法进行用户认证
        将上一步创建的 UsernamePasswordAuthenticationToken 对象传入进行认证
        认证管理器会根据传入的认证信息进行认证，包括验证用户名和密码的正确性以及用户的角色等信息
        如果认证成功，authenticate 对象将包含认证成功的用户信息，包括用户的角色等
        否则，如果认证失败，会抛出 AuthenticationException 异常 Authentication*/
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        //判断是否认证成功
        if (Objects.isNull(authenticate)){
            throw new RuntimeException("用户名或者密码错误!");
        }
        //根据用户ID封装JWT
        LoginSyUser loginSyUser = (LoginSyUser) authenticate.getPrincipal();
        loginSyUser.getSysUser().setPassword(null);
        String userid = loginSyUser.getSysUser().getId().toString();
        String jwt = JwtUtil.createJWT(userid);
        //将用户的登录信息存入到Redis中
        redisCache.setCacheObject("login:" + userid , loginSyUser , 15 , TimeUnit.MINUTES);
        //封装token返回
        Map<String, String> map = new HashMap<>();
        map.put("token",jwt);
        return new ResponseResult(200 , "登录成功" , map);
    }


    /***
     * 退出登录
     * @return 返回结果
     */
    @Override
    public ResponseResult logout(HttpServletRequest request, HttpServletResponse response) {
        //从SecurityContextHolder中获取当前线程认证的用户信息
        UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginSyUser principal = (LoginSyUser) authentication.getPrincipal();
        //销毁Redis中的用户信息
        Long id = principal.getSysUser().getId();
        boolean b = redisCache.deleteObject("login:" + id);
        //销毁SpringSecurity的认证信息

        return null;
    }
}




